from chernc.treediff.diff import match_tree, match_tree_range, match_tree_simple
from chernc.treediff.gumtree.actions.model.insert import Insert
from chernc.treediff.gumtree.actions.model.move import Move
from chernc.treediff.gumtree.actions.model.update import Update
from chernc.treediff.gumtree.actions.simplified_chawathe_script_generator import SimplifiedChawatheScriptGenerator
from chernc.treediff.gumtree.gen.generators.treesitter_tree_generator import TreeSitterTreeGenerator
from chernc.treediff.gumtree.matchers.configuration_options import ConfigurationOptions
from chernc.treediff.gumtree.matchers.gumtree_properties import GumtreeProperties
from chernc.treediff.gumtree.matchers.heuristic.gt.greedy_bottom_up_matcher import GreedyBottomUpMatcher
from chernc.treediff.gumtree.matchers.heuristic.gt.greedy_subtree_matcher import GreedySubtreeMatcher
from chernc.treediff.gumtree.matchers.matchers import Matchers
from chernc.treediff.gumtree.matchers.similarity_metrics import SimilarityMetrics


def parse_tree():
    rust_code = """
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array);
    print_array(&input_array, 10);
}
"""
    tc = TreeSitterTreeGenerator("rust").generate_tree(rust_code)  # Retrieves and applies the default parser for the file
    t = tc.get_root()  # Retrieves the root of the tree

    # Display the tree in an ad-hoc format
    print(t)

    # Display the tree in LISP syntax
    # print(TreeIoUtils.to_lisp(tc).to_string())


def diff_tree():
    src_file = """
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array);
    print_array(&input_array, 10);
}
"""
    dst_file = """
println!("bubble sort the array");
"""

    src = TreeSitterTreeGenerator("rust").generate_tree(src_file)  # Retrieves and applies the default parser for the file
    dst = TreeSitterTreeGenerator("rust").generate_tree(dst_file)  # Retrieves and applies the default parser for the file

    default_matcher = GreedySubtreeMatcher()
    properties = GumtreeProperties()
    properties.put(ConfigurationOptions.st_minprio, 2)
    properties.put(ConfigurationOptions.st_priocalc, "height")
    default_matcher.configure(properties)
    mappings = default_matcher.match_with_new_store(src.get_root(), dst.get_root())  # Computes the mappings between the trees
    print(mappings)


def get_edit_script():

    src_file = """
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array);
    print_array(&input_array, 10);
}
"""
    dst_file = """
println!("bubble sort the array");
"""

    src = TreeSitterTreeGenerator("rust").generate_tree(src_file)  # Retrieves and applies the default parser for the file
    dst = TreeSitterTreeGenerator("rust").generate_tree(dst_file)  # Retrieves and applies the default parser for the file

    default_matcher = GreedySubtreeMatcher()
    properties = GumtreeProperties()
    properties.put(ConfigurationOptions.st_minprio, 2)
    properties.put(ConfigurationOptions.st_priocalc, "height")
    default_matcher.configure(properties)
    mappings = default_matcher.match_with_new_store(src.get_root(), dst.get_root())  # Computes the mappings between the trees

    edit_script_generator = SimplifiedChawatheScriptGenerator()  # Instantiates the simplified Chawathe script generator
    actions = edit_script_generator.compute_actions(mappings)  # Computes the edit script

    for action in actions.actions:
        print(f"========ACTION {action.get_name()}=======")
        if isinstance(action, Update):
            print("Node: ")
            print(action.get_node().to_tree_string())
            print("Value: ")
            print(action.get_value())
        elif isinstance(action, Move):
            print("Node: ")
            print(action.get_node().to_tree_string())
            print("Parent: ")
            print(action.get_parent().to_tree_string())
            print("Pos: ")
            print(action.get_position())
        elif isinstance(action, Insert):
            print("Node: ")
            print(action.get_node().to_tree_string())
            print("Parent: ")
            if action.get_parent() is None:
                print("None")
            else:
                print(action.get_parent().to_tree_string())
            print("Pos: ")
            print(action.get_position())
        else:
            print(action.get_node().to_tree_string())
        # print("===============")


def diff_tree_hard():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
"""
    rhs = """
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("Original array: {:?}", input_array);
    println!("Bubble sort the array");

    bubble_sort(&mut input_array);

    // Print the sorted array
    println!("Sorted array: {:?}", input_array);
}

fn bubble_sort(arry: &mut [i32]) {
    let length = arry.len();
    for i in 0..length {
        for j in 0..length - i - 1 {
            if arry[j] > arry[j + 1] {
                arry.swap(j, j + 1);
            }
        }
    }
}

fn swap_new(left: &mut i32, right: &mut i32) {
    *left = std::mem::replace(right, *left);
}
"""

    src = TreeSitterTreeGenerator("rust").generate_tree(lhs)  # Retrieves and applies the default parser for the file
    dst = TreeSitterTreeGenerator("rust").generate_tree(rhs)  # Retrieves and applies the default parser for the file

    default_matcher = GreedySubtreeMatcher()
    properties = GumtreeProperties()
    properties.put(ConfigurationOptions.st_minprio, 2)
    properties.put(ConfigurationOptions.st_priocalc, "height")
    default_matcher.configure(properties)
    mappings = default_matcher.match_with_new_store(src.get_root(), dst.get_root())  # Computes the mappings between the trees

    bottomup_matcher = GreedyBottomUpMatcher()
    properties = GumtreeProperties()
    properties.put(ConfigurationOptions.bu_minsize, 1000)
    properties.put(ConfigurationOptions.bu_minsim, 0.3)
    bottomup_matcher.configure(properties)
    mappings = bottomup_matcher.match(src.get_root(), dst.get_root(), mappings)  # Computes the mappings between the trees
    print(mappings)

    """
    edit_script_generator = SimplifiedChawatheScriptGenerator()  # Instantiates the simplified Chawathe script generator
    actions = edit_script_generator.compute_actions(mappings)  # Computes the edit script

    for action in actions.actions:
        print(f"========ACTION {action.get_name()}=======")
        if isinstance(action, Update):
            print("Node: ")
            print(action.get_node().to_tree_string())
            print("Value: ")
            print(action.get_value())
        elif isinstance(action, Move):
            print("Node: ")
            print(action.get_node().to_tree_string())
            print("Parent: ")
            print(action.get_parent().to_tree_string())
            print("Pos: ")
            print(action.get_position())
        elif isinstance(action, Insert):
            print("Node: ")
            print(action.get_node().to_tree_string())
            print("Parent: ")
            if action.get_parent() is None:
                print("None")
            else:
                print(action.get_parent().to_tree_string())
            print("Pos: ")
            print(action.get_position())
        else:
            print(action.get_node().to_tree_string())
    """


def tree_diff_api_1():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
"""
    rhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap_new(left: &mut i32, right: &mut i32) {
    *left = std::mem::replace(right, *left);

}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

"""
    s, e = match_tree_range(lhs, rhs)
    print(lhs[s:e])


def tree_diff_api_2():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
fn main() {
    let mut input_array = [12, 43, 9, 13, 67, 98, 101, 89, 3, 35];
    println!("bubble sort the array");

    bubble_sort(&mut input_array, 10);

    // print the array
    print_array(&input_array, 10);
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:25
"""
    rhs = """
fn main() {
    let mut input_array = [
        12,
        43,
        9,
        13,
        67,
        98,
        101,
        89,
        3,
        35
    ];

    bubble_sort(&mut input_array);
    print_array(&input_array, 10);
}
"""
    s, e = match_tree_range(lhs, rhs)
    print(lhs[s:e])


def tree_diff_api_3():
    lhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
use helloworld;
"""
    rhs = """
// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3
fn swap(left: &mut i32, right: &mut i32) {
    let temp = *left;
    *left = *right;
    *right = temp;
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:3

// CHERNC_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
fn bubble_sort(arry: &mut [i32], length: usize) {
    for i in 0..length-1 {
        for j in 0..length-i-1 {
            if arry[j] > arry[j+1] { // changed to use '>' for bubble sort
                let (left, right) = arry.split_at_mut(j + 1); // split the array into two parts
                swap(&mut left[j], &mut right[0]); // swap the elements
            }
        }
    }
}
// CHERNC_END_MARK: /data/wangjun/github/Chern-C/examples/bubblesort/bubblesort.c:10
"""
    s, e = match_tree_range(lhs, rhs)
    print(lhs[s:e])


def tree_diff_api_4():
    lhs = """ 
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:53
struct BlockHeader {
    magic_number: u32,
    bytes: usize,
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:56

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:60
static mut allocated_bytes: usize = 0;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:60

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:66
static mut allocation_limit: i32 = -1;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:66

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:259
fn alloc_test_get_allocated() -> usize {
    allocated_bytes
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:262

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:23
type BlockHeader = struct {
    magic_number: u32,
    bytes: usize,
};
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:23

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:33
const ALLOC_TEST_MAGIC: u32 = 0x72ec82d2;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:33

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:254
fn alloc_test_set_limit(alloc_count: i32) {
    allocation_limit = alloc_count;
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:257

// CHERNC_MARK: /app/examples/smallprimary/framework.h:38
type UnitTestFunction = fn();
// CHERNC_END_MARK: /app/examples/smallprimary/framework.h:38

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:70
fn alloc_test_get_header(ptr: *const u8) -> *const BlockHeader {
    let result = unsafe { (ptr as *const BlockHeader).offset(-1) };
    assert_eq!(result.magic_number, ALLOC_TEST_MAGIC);
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:81

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:44
const FREE_PATTERN: u32 = 0xDEADBEEF;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:44

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:39
const MALLOC_PATTERN: u32 = 0xBAADF00D;
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:39

// CHERNC_MARK: /app/examples/smallprimary/framework.c:31
fn run_test(test: UnitTestFunction) {
    // Turn off any allocation limits that may have been set
    // by a previous test.
    alloc_test_set_limit(-1);

    // Run the test
    test();

    // Check that all memory was correctly freed back during
    // the test.
    assert_eq!(alloc_test_get_allocated(), 0);
}
// CHERNC_END_MARK: /app/examples/smallprimary/framework.c:46

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:85
fn alloc_test_overwrite(ptr: *mut u8, length: usize, pattern: u32) {
    let mut byte_ptr = ptr;
    for i in 0..length {
        let pattern_seq = (i & 3) as i32;
        let b = ((pattern >> (8 * pattern_seq)) & 0xff) as u8;
        unsafe { *byte_ptr.add(i) = b };
    }
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:100

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:150
fn alloc_test_free(ptr: *mut u8) {
    let header = alloc_test_get_header(ptr);
    let block_size = header.bytes;
    assert!(allocated_bytes >= block_size);

    // Trash the allocated block to foil any code that relies on memory
    // that has been freed.
    alloc_test_overwrite(ptr, header.bytes, FREE_PATTERN);

    // Trash the magic number in the block header to stop the same block
    // from being freed again.
    unsafe { (*header).magic_number = 0 };

    // Free the allocated memory.
    unsafe { free(header as *mut std::ffi::c_void) };

    // Update counter
    allocated_bytes -= block_size;
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:184

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:104
fn alloc_test_malloc(bytes: usize) -> *mut u8 {
    let header = unsafe { malloc(std::mem::size_of::<BlockHeader>() + bytes) as *mut BlockHeader };
    if header.is_null() {
        return std::ptr::null_mut();
    }

    unsafe { (*header).magic_number = ALLOC_TEST_MAGIC };
    unsafe { (*header).bytes = bytes };

    // Fill memory with MALLOC_PATTERN, to ensure that code under test
    // does not rely on memory being initialised to zero.
    let ptr = unsafe { header.add(1) };
    alloc_test_overwrite(ptr, bytes, MALLOC_PATTERN);

    // Update counter
    allocated_bytes += bytes;

    // Decrease the allocation limit
    if allocation_limit > 0 {
        allocation_limit -= 1;
    }

    // Skip past the header and return the block itself
    unsafe { header.add(1) }
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:146

// CHERNC_MARK: /app/examples/smallprimary/framework.c:48
fn run_tests(tests: &[fn()]) {
    for test in tests.iter().filter(|&&test| !test.is_null()) {
        run_test(test);
    }
}
// CHERNC_END_MARK: /app/examples/smallprimary/framework.c:55

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:219
fn alloc_test_calloc(nmemb: usize, bytes: usize) -> *mut u8 {
    let total_bytes = nmemb * bytes;
    let result = alloc_test_malloc(total_bytes);
    if result.is_null() {
        return std::ptr::null_mut();
    }
    unsafe { memset(result, 0, total_bytes) };
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:237

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:239
fn alloc_test_strdup(string: &str) -> *mut u8 {
    let result = alloc_test_malloc(string.len() + 1);
    if result.is_null() {
        return std::ptr::null_mut();
    }
    unsafe { strcpy(result, string.as_ptr()) };
    result
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:252

// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:186
fn alloc_test_realloc(ptr: *mut u8, bytes: usize) -> *mut u8 {
    let new_ptr = alloc_test_malloc(bytes);
    if new_ptr.is_null() {
        return std::ptr::null_mut();
    }

    if !ptr.is_null() {
        let header = alloc_test_get_header(ptr);
        let bytes_to_copy = header.bytes;
        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }
        unsafe { memcpy(new_ptr, ptr, bytes_to_copy) };
        alloc_test_free(ptr);
    }

    new_ptr
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:217
"""
    rhs = """
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:23
type BlockHeader = struct {
    magic_number: u32,
    bytes: usize,
};
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:23
"""
    s, e = match_tree_range(lhs, rhs)
    print(lhs[s:e])


def tree_diff_api_5():
    lhs = """ 
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:186
fn alloc_test_free(ptr: *mut u8, bytes: usize) -> *mut u8 {
    let new_ptr = alloc_test_malloc(bytes);
    if new_ptr.is_null() {
        return std::ptr::null_mut();
    }

    if !ptr.is_null() {
        let header = alloc_test_get_header(ptr);
        let bytes_to_copy = header.bytes;
        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }
        unsafe { memcpy(new_ptr, ptr, bytes_to_copy) };
        alloc_test_free(ptr);
    }

    new_ptr
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:217
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:186
fn alloc_test_realloc(ptr: *mut u8, bytes: usize) -> *mut u8 {
    let new_ptr = alloc_test_malloc(bytes);
    if new_ptr.is_null() {
        return std::ptr::null_mut();
    }

    if !ptr.is_null() {
        let header = alloc_test_get_header(ptr);
        let bytes_to_copy = header.bytes;
        if bytes_to_copy > bytes {
            bytes_to_copy = bytes;
        }
        unsafe { memcpy(new_ptr, ptr, bytes_to_copy) };
        alloc_test_free(ptr);
    }

    new_ptr
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:217
"""
    rhs = """
// CHERNC_MARK: /app/examples/smallprimary/alloc-testing.c:23
if new_ptr.is_null() {
    return std::ptr::null_mut();
}
// CHERNC_END_MARK: /app/examples/smallprimary/alloc-testing.c:23
"""
    s, e = match_tree_range(lhs, rhs)
    print(lhs[s:e])


def tree_diff_api_6():
    lhs = "type ArrayListCompareFunc = fn(ArrayListValue, ArrayListValue) -> i32;"
    rhs = "type ArrayListEqualFunc = fn(ArrayListValue, ArrayListValue) -> i32;"
    ret = match_tree_simple(
        source=lhs,
        destination=rhs,
    )
    if ret is None:
        return None
    src_root, dst_root, mappings = ret
    sim = SimilarityMetrics.jaccard_similarity(src_root, dst_root, mappings)
    print(mappings)
    print(sim)


def tree_diff_api_7():
    lhs = "// Dummy translation for test.c-80:81"
    rhs = "// Dummy translation for test.c-83:84"
    ret = match_tree_simple(
        source=lhs,
        destination=rhs,
    )
    if ret is None:
        return None
    src_root, dst_root, mappings = ret
    sim = SimilarityMetrics.jaccard_similarity(src_root, dst_root, mappings)
    print(mappings)
    print(sim)


def tree_diff_api_8():
    lhs = """
fn append(&mut self, data: ArrayListValue) -> bool {
    self.insert(self.length, data)
}
"""
    rhs = """
pub fn append(&mut self, data: ArrayListValue) -> bool { // line 170
    self.insert(self.length, data)
}
"""
    ret = match_tree_simple(
        source=lhs,
        destination=rhs,
    )
    if ret is None:
        return None
    src_root, dst_root, mappings = ret
    sim = SimilarityMetrics.jaccard_similarity(src_root, dst_root, mappings)
    print(mappings)
    print(sim)

def tree_diff_api_9():
    lhs = """
fn append(&mut self, data: ArrayListValue) -> bool {
        self.insert(self.length, data)
    }
"""
    rhs = """
fn prepend(&mut self, data: ArrayListValue) -> bool {
        self.insert(0, data)
    }
"""
    ret = match_tree_simple(
        source=lhs,
        destination=rhs,
    )
    if ret is None:
        return None
    src_root, dst_root, mappings = ret
    sim = SimilarityMetrics.jaccard_similarity(src_root, dst_root, mappings)
    print(mappings)
    print(sim)


if __name__ == "__main__":
    # diff_tree()
    # get_edit_script()
    # diff_tree_hard()

    # tree_diff_api_1()
    # tree_diff_api_2()
    # tree_diff_api_3()
    # tree_diff_api_4()
    # tree_diff_api_5()
    # tree_diff_api_6()
    # tree_diff_api_7()
    # tree_diff_api_8()
    tree_diff_api_9()
